package com.yuncheng.system.login.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.yuncheng.common.api.BeforeLoginAPI;
import com.yuncheng.common.utils.CommonUtils;
import com.yuncheng.common.utils.EntityUtil;
import com.yuncheng.constant.CacheConstant;
import com.yuncheng.constant.CommonConstant;
import com.yuncheng.exception.SystemException;
import com.yuncheng.rest.RestClient;
import com.yuncheng.sms.api.SmsAPI;
import com.yuncheng.system.api.SystemAPI;
import com.yuncheng.system.login.model.SysLoginModel;
import com.yuncheng.system.login.model.UserLoginType;
import com.yuncheng.system.login.model.WxAppProperties;
import com.yuncheng.system.login.service.LoginService;
import com.yuncheng.system.login.util.EncryptedString;
import com.yuncheng.system.login.util.RandImageUtil;
import com.yuncheng.system.orguser.entity.SysUser;
import com.yuncheng.system.orguser.service.ISysUserService;
import com.yuncheng.system.userlock.service.SysUserLockService;
import com.yuncheng.system.userlock.service.UserLoader;
import com.yuncheng.utils.*;
import com.yuncheng.vo.HttpResult;
import com.yuncheng.vo.LoginUser;
import com.yuncheng.vo.SysYmlProperties;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.shiro.SecurityUtils;
import org.mybatis.spring.MyBatisSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestController
@RequestMapping(CommonConstant.PREFIX_SYSTEM + "")
@Api(tags = "用户登录接口")
public class LoginController {

    private static final Logger log = LoggerFactory.getLogger(LoginController.class);

    @Resource
    private LoginService loginService;

    @Resource
    private ISysUserService sysUserService;

    @Autowired
    private SysUserLockService sysUserLockService;

    @Autowired
    private UserLoader userLoader;

    @Resource
    private SystemAPI systemAPI;

    @Resource
    private SmsAPI smsAPI;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private CaptchaService captchaService;

    @Resource
    private RestClient restClient;

    @Resource
    private SysYmlProperties sysYmlProperties;

    @Resource
    private WxAppProperties wxProperties;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    public static final Pattern MD5_STR_PATTERN = Pattern.compile("^[a-f0-9]{32}$");

    private boolean isMd5String(String s) {
        if (null != s) {
            Matcher m = MD5_STR_PATTERN.matcher(s);
            return m.matches();
        }
        return false;
    }

    @ApiOperation(value = "带验证码登录")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public HttpResult<?> login(@RequestBody SysLoginModel sysLoginModel) {
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();



        if (!StringUtils.isEmpty(sysLoginModel.getCaptchaVerification())) {
            CaptchaVO captchaVO = new CaptchaVO();
            captchaVO.setCaptchaVerification(sysLoginModel.getCaptchaVerification());
            ResponseModel responseModel = captchaService.verification(captchaVO);
            if (!responseModel.isSuccess()) {
                //验证码校验失败，返回信息告诉前端
                //repCode  0000  无异常，代表成功
                //repCode  9999  服务器内部异常
                //repCode  0011  参数不能为空
                //repCode  6110  验证码已失效，请重新获取
                //repCode  6111  验证失败
                //repCode  6112  获取验证码失败,请联系管理员
                if("9999".equals(responseModel.getRepCode())){
                    return HttpResult.error(I18nUtil.message("captcha.repCode_9999"));
                }else if("0011".equals(responseModel.getRepCode())){
                    return HttpResult.error(I18nUtil.message("captcha.repCode_0011"));
                }else if("6110".equals(responseModel.getRepCode())){
                    return HttpResult.error(I18nUtil.message("captcha.repCode_6110"));
                }else if("6111".equals(responseModel.getRepCode())){
                    return HttpResult.error(I18nUtil.message("captcha.repCode_6111"));
                }else if("6112".equals(responseModel.getRepCode())){
                    return HttpResult.error(I18nUtil.message("captcha.repCode_6112"));
                }else {
                    return HttpResult.error(responseModel.getRepMsg());
                }
            }
        } else if (sysLoginModel.getCaptcha() != null) {
            String lowerCaseCaptcha = sysLoginModel.getCaptcha().toLowerCase();
            String realKey = CommonUtils.md5DigestAsHex(lowerCaseCaptcha + sysLoginModel.getCheckKey());
            Object checkCode = redisUtil.get(realKey);
            if (checkCode == null || !checkCode.toString().toLowerCase().equals(lowerCaseCaptcha)) {
                return  HttpResult.error(I18nUtil.message("user.captcha.error"));
            }
        } else {
            return  HttpResult.error(I18nUtil.message("user.captcha.invalid"));
        }


        SysUser sysUser = sysUserService.getUserByName(username);
        Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
        for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
            try {
                String r = entry.getValue().execute(sysUser);
                if (r != null) {
                    return  HttpResult.error(r);
                }
            } catch (Exception e) {
                return  HttpResult.error(e.getMessage());
            }
        }

        //校验用户名或密码是否正确
        String userpassword = isMd5String(sysUser.getPassword()) ? CommonUtils.md5DigestAsHex(password) : CommonUtils.md5Crypt(password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            systemAPI.addLog(username,"登录失败", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return  HttpResult.error(I18nUtil.message("user.password.not.match"));
        }

        //用户登录信息
        HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
        systemAPI.addLog(username,"登录成功", CommonConstant.LOG_TYPE_LOGIN,  CommonConstant.OPERATE_TYPE_LOGIN);

        // TODO 升级到VUE3后，登录只需要返回Token就可以
        return httpResult;
    }

    @ApiOperation(value = "带验证码登录")
    @RequestMapping(value = "/login2", method = RequestMethod.POST)
    public HttpResult<?> login2(@RequestBody SysLoginModel sysLoginModel) {
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        SysUser sysUser = userLoader.loadUserByUsername(username);

        Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
        for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
            try {
                String r = entry.getValue().execute(sysUser);
                if (r != null) {
                    return  HttpResult.error(r);
                }
            } catch (Exception e) {
                return  HttpResult.error(e.getMessage());
            }
        }

        String currentPassword = sysUser.getPassword();
        String currentSalt = sysUser.getSalt();
        String weihuTokenMsg = "";

        //校验用户名或密码是否正确
        boolean isMD5Password = isMd5String(currentPassword);
        String userpassword = isMD5Password ? CommonUtils.md5DigestAsHex(password) : CommonUtils.md5Crypt(password, currentSalt);
        String syspassword = currentPassword;
        if (!syspassword.equals(userpassword)) {
            sysUserLockService.passwordError(sysUser);
            systemAPI.addLog(username,"登录失败", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return  HttpResult.error(I18nUtil.message("user.password.not.match"));
        }
        sysUserLockService.passwordSuccess(sysUser);

        if (isMD5Password) {
            // 登录成功，密码是MD5格式的，先转换密码格式为crypt的
            String salt = CommonUtils.getMd5Salt();
            String newCryptPassword = CommonUtils.md5Crypt(password, salt);

            //保存新密码到数据库
            SysUser updatePassword = new SysUser();
            updatePassword.setId(sysUser.getId());
            updatePassword.setSalt(salt);
            updatePassword.setPassword(newCryptPassword);
            sysUserService.updateById(updatePassword);

            // 重新加载用户对象，确保使用新密码
            sysUser = sysUserService.getUserByName(username);

        }

        //用户登录信息
        HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
        systemAPI.addLog(username,"登录成功" + weihuTokenMsg, CommonConstant.LOG_TYPE_LOGIN,  CommonConstant.OPERATE_TYPE_LOGIN);

        // TODO 升级到VUE3后，登录只需要返回Token就可以
        return httpResult;
    }

    @ApiOperation(value = "机器登录")
    @RequestMapping(value = "/robotLogin", method = RequestMethod.POST)
    public HttpResult<?> robotLogin(@RequestBody SysLoginModel sysLoginModel) {
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        SysUser sysUser = userLoader.loadUserByUsername(username);

        Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
        for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
            try {
                String r = entry.getValue().execute(sysUser);
                if (r != null) {
                    return  HttpResult.error(r);
                }
            } catch (Exception e) {
                return  HttpResult.error(e.getMessage());
            }
        }

        String currentPassword = sysUser.getPassword();
        String currentSalt = sysUser.getSalt();
        String weihuTokenMsg = "";

        //校验用户名或密码是否正确
        boolean isMD5Password = isMd5String(currentPassword);
        String userpassword = isMD5Password ? CommonUtils.md5DigestAsHex(password) : CommonUtils.md5Crypt(password, currentSalt);
        String syspassword = currentPassword;
        if (!syspassword.equals(userpassword)) {
            sysUserLockService.passwordError(sysUser);
            systemAPI.addLog(username,"登录失败", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return  HttpResult.error(I18nUtil.message("user.password.not.match"));
        }
        sysUserLockService.passwordSuccess(sysUser);

        if (isMD5Password) {
            // 登录成功，密码是MD5格式的，先转换密码格式为crypt的
            String salt = CommonUtils.getMd5Salt();
            String newCryptPassword = CommonUtils.md5Crypt(password, salt);

            //保存新密码到数据库
            SysUser updatePassword = new SysUser();
            updatePassword.setId(sysUser.getId());
            updatePassword.setSalt(salt);
            updatePassword.setPassword(newCryptPassword);
            sysUserService.updateById(updatePassword);

            // 重新加载用户对象，确保使用新密码
            sysUser = sysUserService.getUserByName(username);

        }

        //用户登录信息
        HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
        systemAPI.addLog(username,"登录成功" + weihuTokenMsg, CommonConstant.LOG_TYPE_LOGIN,  CommonConstant.OPERATE_TYPE_LOGIN);

        // TODO 升级到VUE3后，登录只需要返回Token就可以
        return httpResult;
    }

    @ApiOperation(value = "APP账号登录")
    @RequestMapping(value = "/appUserLogin", method = RequestMethod.POST)
    public HttpResult<?> appUserLogin(@RequestBody SysLoginModel sysLoginModel) {
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        SysUser sysUser = userLoader.loadUserByPhone(username);

        Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
        for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
            try {
                String r = entry.getValue().execute(sysUser);
                if (r != null) {
                    return  HttpResult.error(r);
                }
            } catch (Exception e) {
                return  HttpResult.error(e.getMessage());
            }
        }

        String currentPassword = sysUser.getPassword();
        String currentSalt = sysUser.getSalt();
        String weihuTokenMsg = "";

        //校验用户名或密码是否正确
        boolean isMD5Password = isMd5String(currentPassword);
        String userpassword = isMD5Password ? CommonUtils.md5DigestAsHex(password) : CommonUtils.md5Crypt(password, currentSalt);
        String syspassword = currentPassword;
        if (!syspassword.equals(userpassword)) {
            sysUserLockService.passwordError(sysUser);
            systemAPI.addLog(username,"登录失败", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return  HttpResult.error(I18nUtil.message("user.password.not.match"));
        }
        sysUserLockService.passwordSuccess(sysUser);

        if (isMD5Password) {
            // 登录成功，密码是MD5格式的，先转换密码格式为crypt的
            String salt = CommonUtils.getMd5Salt();
            String newCryptPassword = CommonUtils.md5Crypt(password, salt);

            //保存新密码到数据库
            SysUser updatePassword = new SysUser();
            updatePassword.setId(sysUser.getId());
            updatePassword.setSalt(salt);
            updatePassword.setPassword(newCryptPassword);
            sysUserService.updateById(updatePassword);

            // 重新加载用户对象，确保使用新密码
            sysUser = sysUserService.getUserByName(username);

        }

        //用户登录信息
        HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
        systemAPI.addLog(username,"登录成功" + weihuTokenMsg, CommonConstant.LOG_TYPE_LOGIN,  CommonConstant.OPERATE_TYPE_LOGIN);

        // TODO 升级到VUE3后，登录只需要返回Token就可以
        return httpResult;
    }

    /**
     * 退出登录
     */
    @ApiOperation(value = "退出登录")
    @RequestMapping(value = "/logout")
    public HttpResult<Object> logout(HttpServletRequest request) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return HttpResult.error(I18nUtil.message("user.logout.error"));
        }

        String username = JwtUtil.getUsername(token);
        LoginUser sysUser = systemAPI.getUserByName(username);

        systemAPI.addLog(username, "退出成功", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGOUT);
        //清空用户登录Token缓存
        redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
        //清空oauth2记录的token
        if (sysYmlProperties.getOauth2Client() != null) {
            for (String key : sysYmlProperties.getOauth2Client().keySet()) {
                redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token + CommonConstant.OAUTH2_TOKEN + key);
            }
        }
        //调用shiro的logout
        SecurityUtils.getSubject().logout();
        if (sysUser != null) {
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
        }
        return HttpResult.ok(I18nUtil.message("user.logout.success"));
    }

    @ApiOperation(value = "获取登录用户信息")
    @GetMapping(value = "/getUserInfo")
    public HttpResult<?> getUserInfo() {
        SysUser sysUser = sysUserService.getUserByName(ThreadContextHelper.getCurrentUser().getLoginName());

        sysUserService.checkBackRole(sysUser);

        return HttpResult.ok(sysUser);
    }

    /**
     * 短信登录接口
     */
    @ApiOperation(value = "短信登录")
    @PostMapping(value = "/sms")
    public HttpResult<?> sms(@RequestBody JSONObject jsonObject) {
        return HttpResult.error("无效接口");
    }


    /**
     * 手机号登录接口
     *
     * @param jsonObject
     * @return
     */
    @ApiOperation(value = "手机号登录")
    @PostMapping("/phoneLogin")
    public HttpResult<?> phoneLogin(@RequestBody JSONObject jsonObject) {
        return HttpResult.error("无效接口");
    }




    /**
     * 获取加密字符串
     *
     * @return
     */
    @GetMapping(value = "/getEncryptedString")
    public HttpResult<Map<String, String>> getEncryptedString() {
        HttpResult<Map<String, String>> httpResult = new HttpResult<Map<String, String>>();
        Map<String, String> map = new HashMap<String, String>();
        map.put("key", EncryptedString.key);
        map.put("iv", EncryptedString.iv);
        httpResult.setResult(map);
        return httpResult;
    }


    /**
     * 后台生成图形验证码 ：有效
     */
    @ApiOperation(value = "获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public HttpResult<?> randomImage(@PathVariable("key") String key) {
        HttpResult<String> res = new HttpResult<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = CommonUtils.md5DigestAsHex(lowerCaseCode + key);
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            return  HttpResult.error(I18nUtil.message("user.captcha.error"));

        }
        return res;
    }

    /**
     * 图形验证码
     */
    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
    public HttpResult<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return HttpResult.error(I18nUtil.message("user.captcha.invalid"));
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = CommonUtils.md5DigestAsHex(lowerCaseCaptcha + checkKey);
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return HttpResult.error(I18nUtil.message("user.captcha.error"));
        }
        return HttpResult.ok();
    }

    /**
     * app登录
     */
    @ApiOperation(value = "APP登录")
    @RequestMapping(value = "/mLogin", method = RequestMethod.POST)
    public HttpResult<?> mLogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        return HttpResult.error("无效接口");
    }

    /**
     * 后台系统获取token登录,非人机交互登录
     */
    @ApiOperation(value = "机器登录2")
    @RequestMapping(value = "/robotLogin2", method = RequestMethod.POST)
    public HttpResult<?> robotLogin2(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        return HttpResult.error("无效接口");
    }

    ///////////////////////////////////////移动APP登录，包括小程序开始////////////////////////////////////////////

    @ApiOperation(value = "第三方登录")
    @RequestMapping(value = "/thirdPartLogin", method = RequestMethod.POST)
    public HttpResult<?> thirdPartLogin(@RequestBody JSONObject jsonObject) throws Exception {
        return HttpResult.error("无效接口");
    }

    /**
     * 微信小程序第三方登录，或微信APP安全登录
     * @param loginType MP_WEIXIN(1, "WX小程序登录"), APP_WEIXIN(2, "WX第三方登录")
     */
    private HttpResult<?> wechatSafeLogin(Integer loginType, String userInfo, String raw) throws Exception {
        //微信第三方登录
        JSONObject thirdPartJsonObject = JSONObject.parseObject(raw);
        String code = thirdPartJsonObject.getString("code");
        String nickName = "";
        String gender = "0";
        String avatarUrl = "";
        if(userInfo!=null){
            JSONObject userInfoObject = JSONObject.parseObject(userInfo);
            nickName = userInfoObject.getString("nickName");
            gender = userInfoObject.getString("gender");
            avatarUrl = userInfoObject.getString("avatarUrl");
        }

        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + (UserLoginType.MP_WEIXIN.getCode() == loginType ? wxProperties.getMiniAppId() : wxProperties.getAppId()) +
                "&secret=" + (UserLoginType.MP_WEIXIN.getCode() == loginType ? wxProperties.getMiniAppSecret() : wxProperties.getAppSecret()) +
                "&grant_type=authorization_code&js_code=" + code;

        String body = restClient.doPost(url, null, new ParameterizedTypeReference<String>() { });
        JSONObject jsonObject = JSONObject.parseObject(body);
        Integer errcode = jsonObject.getInteger("errcode");
        if (errcode == null || errcode == 0) {
            String openid = jsonObject.getString("openid");
            String session_key = jsonObject.getString("session_key");
            List<SysUser>  sysUserList = sysUserService.getUserByThirdId(loginType+"",openid);
            SysUser sysUser = null;
            if( sysUserList==null || sysUserList.size()==0 ){  //若用户为空，则注册此用户
                sysUser = new SysUser();
                sysUser.setUsername(CommonUtils.generate());
                String salt = CommonUtils.getMd5Salt();//RandomUtil.randomString(8);
                sysUser.setSalt(salt);
                String passwordEncode = CommonUtils.md5Crypt("123456", salt);
                sysUser.setPassword(passwordEncode);
                sysUser.setThirdType(loginType+"");
                sysUser.setThirdId(openid);
                sysUser.setAvatar(avatarUrl);
                sysUser.setRealname(nickName);
                sysUser.setSex(Integer.valueOf(gender));
                sysUser.setStatus(1);
//                sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
                EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.insert);
                sysUserService.saveThirdUser(sysUser);
            }else{
                sysUser = sysUserList.get(0);
                EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.update);
                sysUserService.updateById(sysUser);
            }

            // 校验用户信息
//            Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
//            for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
//                try {
//                    String r = entry.getValue().execute(sysUser);
//                    if (r != null) {
//                        return HttpResult.error(r);
//                    }
//                } catch (Exception e) {
//                    return HttpResult.error(e.getMessage());
//                }
//            }

            HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
            systemAPI.addLog(openid,"登录成功[小程序]", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return httpResult;

        } else {
            log.error("[微信登录] 回复失败 回复报文：" + body);
            throw new SystemException("微信第三方登录错误");
        }
    }

    /**
     * 微信公众号浏览器H5登录
     */
    private HttpResult<?> wechatH5Login(Integer loginType, String userInfo, String raw) throws Exception {
        //H5 微信公众号网页登录
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
                + wxProperties.getH5AppId() + "&secret=" + wxProperties.getH5AppSecret() + "&code=" + raw + "&grant_type=authorization_code";
        String json = restClient.doPost(url, null, new ParameterizedTypeReference<String>() { });
        JSONObject jsonObject = JSONObject.parseObject(json);
        Integer errcode = jsonObject.getInteger("errcode");
        if (errcode == null || errcode == 0) {
            String openid = jsonObject.getString("openid");
            List<SysUser>  sysUserList = sysUserService.getUserByThirdId(UserLoginType.H5_WEIXIN.getCode()+"",openid);
            SysUser sysUser = null;
            if( sysUserList==null || sysUserList.size()==0 ){
                String userAccessToken = jsonObject.getString("access_token");
                String url2 = "https://api.weixin.qq.com/sns/userinfo?access_token=" + userAccessToken + "&openid=" + openid + "&lang=zh_CN";
                String userInfoJson = restClient.doPost(url2, null, new ParameterizedTypeReference<String>() { });
                JSONObject userInfoJsonObject = JSONObject.parseObject(userInfoJson);
                sysUser = new SysUser();
                sysUser.setUsername(CommonUtils.generate());
                String salt = CommonUtils.getMd5Salt();//RandomUtil.randomString(8);
                sysUser.setSalt(salt);
                String passwordEncode = CommonUtils.md5Crypt("123456", salt);
                sysUser.setPassword(passwordEncode);
                sysUser.setThirdType(UserLoginType.H5_WEIXIN.getCode()+"");
                sysUser.setThirdId(openid);
                sysUser.setAvatar(userInfoJsonObject.getString("headimgurl"));
                sysUser.setRealname(userInfoJsonObject.getString("nickname"));
                sysUser.setSex(Integer.valueOf(userInfoJsonObject.getInteger("sex")));
                sysUser.setStatus(1);
//                sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
                EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.insert);
                sysUserService.saveThirdUser(sysUser);
            }else{
                sysUser = sysUserList.get(0);
                EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.update);
                sysUserService.updateById(sysUser);
            }

            // 校验用户信息
//            Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
//            for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
//                try {
//                    String r = entry.getValue().execute(sysUser);
//                    if (r != null) {
//                        return HttpResult.error(r);
//                    }
//                } catch (Exception e) {
//                    return HttpResult.error(e.getMessage());
//                }
//            }

            HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
            systemAPI.addLog(openid,"登录成功[微信公众号H5]", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
            return httpResult;

        } else {
            log.error("[微信公众号浏览器H5登录] 回复失败 回复报文：" + json);
            throw new SystemException("微信公众号浏览器H5登录错误");
        }
    }

    /**
     * 微信APP登录
     */
    private HttpResult<?> wechatAppLogin(Integer loginType, String userInfo, String raw) throws Exception{
        //UNI-APP 的 微信APP登录 APPSecret是保存在前端的。这点非常不安全。但是用了他的框架，也没有办法
        String nickName = "";
        String gender = "0";
        String avatarUrl = "";
        if(userInfo!=null){
            JSONObject userInfoObject = JSONObject.parseObject(userInfo);
            nickName = userInfoObject.getString("nickName");
            gender = userInfoObject.getString("gender");
            avatarUrl = userInfoObject.getString("avatarUrl");
        }
        JSONObject jsonObject = JSONObject.parseObject(raw);
        JSONObject authResult = jsonObject.getJSONObject("authResult");
        String openid = authResult.getString("openid");
        List<SysUser>  sysUserList = sysUserService.getUserByThirdId(UserLoginType.APP_WEIXIN.getCode()+"",openid);
        SysUser sysUser = null;
        if( sysUserList==null || sysUserList.size()==0 ){
            sysUser = new SysUser();
            sysUser.setUsername(CommonUtils.generate());
            String salt = CommonUtils.getMd5Salt();
            sysUser.setSalt(salt);
            String passwordEncode = CommonUtils.md5Crypt("123456", salt);
            sysUser.setPassword(passwordEncode);
            sysUser.setThirdType(UserLoginType.APP_WEIXIN.getCode()+"");
            sysUser.setThirdId(openid);
            sysUser.setAvatar(avatarUrl);
            sysUser.setRealname(nickName);
            sysUser.setSex(Integer.valueOf(gender));
            sysUser.setStatus(1);
//            sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
            EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.insert);
            sysUserService.saveThirdUser(sysUser);
        }else{
            sysUser = sysUserList.get(0);
            EntityUtil.setSysProperties(sysUser, EntityUtil.OpType.update);
            sysUserService.updateById(sysUser);
        }

        // 校验用户信息
//            Map<String, BeforeLoginAPI> beforeLoginMap = SpringContextUtils.getApplicationContext().getBeansOfType(BeforeLoginAPI.class);
//            for (Map.Entry<String, BeforeLoginAPI> entry : beforeLoginMap.entrySet()) {
//                try {
//                    String r = entry.getValue().execute(sysUser);
//                    if (r != null) {
//                        return HttpResult.error(r);
//                    }
//                } catch (Exception e) {
//                    return HttpResult.error(e.getMessage());
//                }
//            }

        HttpResult<JSONObject> httpResult = loginService.userInfo(sysUser);
        systemAPI.addLog(openid,"登录成功[微信APP]", CommonConstant.LOG_TYPE_LOGIN, CommonConstant.OPERATE_TYPE_LOGIN);
        return httpResult;
    }

    @ApiOperation(value = "APP账号登录2")
    @RequestMapping(value = "/appUserLogin2", method = RequestMethod.POST)
    public HttpResult<?> appUserLogin2(@RequestBody JSONObject jsonObject ) throws Exception{
        return HttpResult.error("无效接口");
    }
    ///////////////////////////////////////移动APP登录，包括小程序结束////////////////////////////////////////////

}
